#pragma once

#include <uv.h>
#include <string>
#include <memory>
#include <vector>
#include <log.h>
#include <header.h>
#include <iostream>

enum class SESSION {
	DISCONNECT = 0,
	CONNECTED,
};

struct header{

	char version;
	char id;
	char reserved_1; //保留
	char reserved_2; //保留
	uint32_t counter;
	size_t len;

};

struct Protocal{
	header head;
	std::vector<char> body;

	//std::unique_ptr<char> encode(std::string s="");
	std::unique_ptr<char> encode(char type, uint32_t bounds, size_t data_size, std::vector<char>& data);
	//将字节流转换序列化未protocal对象
	void decode(std::vector<char>);
	std::string getjson();
	std::vector<char> getbinary();
};

size_t chararr_combined_to_sizet(const char* arr, int beginByteIndex, int size);

class Session
{
	private:
		int mSessionId;
		SESSION mSt;
		std::shared_ptr<uv_tcp_t> mClient;
		std::vector<char> mIn;

	public:
		Session(int id);
        Session(const Session&)=delete;
		virtual ~Session();

		SESSION status();
		void setStatus(SESSION s);
		int GetSessionID();
		bool isComplete(const uv_buf_t* buf, size_t size);
		std::vector<char> getIn(){return mIn;}
		std::shared_ptr<uv_tcp_t> getSocket();
		//重写该方法，实现对接收的数据的处理
		virtual void doWork(const Protocal& data);
		virtual void doSend(char type, uint32_t bounds, std::vector<char>& body);
		void start(std::shared_ptr<uv_tcp_t> handler);
		
};


//-------------------------------------------------------------------------------

static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf)
{
	buf->base = (char*)malloc(size);
	buf->len = size;
}

static void read_cb(uv_stream_t* s, ssize_t size, const uv_buf_t* buf)
{
	Session* ses = reinterpret_cast<Session*>(s->data);
	if (size > 0) {
		ses->setStatus(SESSION::CONNECTED);
		if (ses->isComplete(buf, size)) {
			Protocal p;
			std::vector<char> data = ses->getIn();
			p.decode(data);
			ses->doWork(p);
		}
	}
	if (size < 0) {
        if (size == UV_EOF) {
            ALOGD("socket eof : %s\n", uv_err_name(size));
        }
		if (size == UV_ECONNRESET) {
			ALOGD("Client[ %d ] Disconnect!!!", ses->GetSessionID());
			//设置session状态为disconnect，便于外部通过状态对session进行管理
			ses->setStatus(SESSION::DISCONNECT);
		}
		uv_read_stop(s);
	}
    //每次read完，需要手动释放alloc_cb中分配的内存
	free(buf->base);
}

static void write_cb(uv_write_t* w, int status)
{
	if (status != 0) {
		ALOGE("发送字节失败!!! %s\n", uv_err_name(status));
	}
	ALOGD("发送成功!!!");

	if (w->data) {
		delete[] (char*)w->data;
	}

	delete w;
}

static void close_cb(uv_handle_t* handle)
{
		delete handle;
}
